/*
gamesession 包定义了游戏会话的核心接口、状态枚举、配置结构及基础实现，
用于管理游戏会话的生命周期（创建、玩家加入/移除、状态流转）和核心功能（消息广播、状态查询），
是游戏多玩家交互场景的基础组件。
*/
package gamesession

import (
	"errors" // 用于定义会话操作相关的错误
	"gameServer/eventbus"
	"gameServer/log"
	"sync" // 提供读写锁，确保会话在并发环境下的安全操作
	"time" // 用于记录会话创建时间和处理超时逻辑
)

// SessionState 会话状态枚举，定义了游戏会话从创建到结束的完整生命周期状态
type SessionState int

// 会话状态常量，覆盖会话的核心生命周期阶段
const (
	StateIdle     SessionState = iota // 0: 空闲状态（刚创建，未开始匹配或等待玩家）
	StateMatching                     // 1: 匹配中（主动寻找其他玩家加入）
	StateReady                        // 2: 准备开始（玩家数量满足最小要求，等待启动指令或自动启动）
	StatePlaying                      // 3: 游戏中（会话已启动，玩家正在进行游戏）
	StateFinished                     // 4: 游戏结束（会话完成，可销毁或归档）
	StatePaused                       // 4: 已暂停（游戏暂停状态）                     // 5: 游戏结束（会话完成，可销毁或归档）
)

// String 返回状态字符串表示
func (s SessionState) String() string {
	// 这里是一个很不错的go特性，go通过这种实现函数的方法，把函数归到对应类型中，那个类型就可以执行，类似C#的tool类
	// 不过我记得C++也有一个工具类似手法来着，友元？那个太封闭了，还是算了吧
	switch s {
	case StateIdle:
		return "idle"
	case StateMatching:
		return "matching"
	case StateReady:
		return "ready"
	case StatePlaying:
		return "playing"
	case StateFinished:
		return "finished"
	default:
		return "unknown"
	}
}

// GameSession 游戏会话核心接口，定义了会话必须实现的功能契约，
// 涵盖会话标识、玩家管理、状态控制、消息处理等核心能力，适配各类游戏会话场景
type GameSession interface {
	// 会话标识与基础信息：获取会话唯一ID、当前状态、创建时间
	ID() string          // 返回会话唯一标识（如"session_123456"）
	State() SessionState // 返回会话当前状态（如StatePlaying）
	CreateAt() time.Time // 返回会话创建时间（用于计算会话存活时长）
	StartAt() *time.Time  // 返回会话启动时间（nil表示未启动）

	// 玩家管理：添加、移除玩家，查询玩家列表和数量
	AddPlayer(playerID string) error    // 向会话添加玩家，失败返回错误（如状态不允许、满员）
	RemovePlayer(playerID string) error // 从会话移除玩家，失败返回错误（如玩家不存在）
	GetPlayers() []string               // 返回当前会话中所有玩家的ID列表
	PlayerCount() int                   // 返回当前会话中的玩家数量
	GetConfig() SessionConfig          // 返回会话配置信息

	// 会话控制：启动、暂停、恢复、结束会话（核心生命周期操作）
	Start() error  // 启动会话（从StateReady转为StatePlaying），失败返回错误（如状态不允许）
	Pause() error  // 暂停会话（仅StatePlaying状态可用），失败返回错误
	Resume() error // 恢复暂停的会话（从暂停状态回到StatePlaying），失败返回错误
	End() error    // 结束会话（转为StateFinished），失败返回错误

	// 状态查询：判断会话当前是否可执行特定操作（如加入玩家、启动游戏）
	IsFull() bool  // 判断会话是否已达最大玩家数（无法再加入新玩家）
	IsEmpty() bool // 判断会话是否无玩家（可销毁或重新匹配）
	CanJoin() bool // 判断当前是否允许新玩家加入（状态和人数均满足条件）
	IsExpired(timeout time.Duration) bool // 判断会话是否已过期（超过配置的超时时间）

	// 消息处理：向玩家发送消息（单播、广播）
	Broadcast(message []byte) error                   // 向会话内所有玩家广播消息，失败返回错误
	SendPlayer(playerID string, message []byte) error // 向指定玩家发送单播消息，失败返回错误
}

// SessionConfig 会话配置结构体，用于初始化会话时定义核心参数，
// 控制会话的玩家数量限制、自动行为（如自动启动）、超时等规则
type SessionConfig struct {
	MaxPlayers    int           `json:"max_players"`   // 会话最大玩家数（超过则无法加入新玩家）
	MinPlayers    int           `json:"min_players"`   // 会话启动的最小玩家数（不足则无法启动）
	Timeout       time.Duration `json:"timeout"`       // 会话超时时间（如匹配超时、无操作超时）
	AutoStart     bool          `json:"auto_start"`    // 是否自动启动（玩家数达MinPlayers时自动转为StateReady并启动）
	Reconnectable bool          `json:"reconnectable"` // 玩家是否可重连（断开后能否重新加入当前会话）
}

// BaseSession GameSession接口的基础实现，封装了会话的通用逻辑（如玩家管理、状态控制），
// 可作为具体游戏会话（如斗地主、MOBA）的嵌入结构体，避免重复实现通用功能
type BaseSession struct {
	id                 string          // 会话唯一标识（通过NewBaseSession传入，确保全局唯一）
	state              SessionState    // 会话当前状态（初始为StateIdle）
	config             SessionConfig   // 会话配置（控制玩家数量、自动启动等规则）
	players            map[string]bool // 存储当前会话中的玩家ID（key为playerID，value无实际意义，仅用于快速判断存在性）
	createAt           time.Time       // 会话创建时间（初始化时自动设置为当前时间）
	startTime          time.Time
	pauseTime          time.Time
	resumeTime         time.Time
	totalPauseDuration time.Duration
	totalDuration      time.Duration
	endTime            time.Time
	mu                 sync.RWMutex      // 读写锁：读操作（如查状态、查玩家）用RLock，写操作（如加玩家、改状态）用Lock
	eventBus           eventbus.EventBus // 事件总线 发布通知
}

// 在 BaseSession 中添加缺失的方法
func (s *BaseSession) CreateAt() time.Time {
	return s.createAt // 假设 BaseSession 有一个 createdAt 字段
}
// 在session.go中添加SetState方法
func (s *BaseSession) SetState(newState SessionState) {
	s.mu.Lock()
	defer s.mu.Unlock()
	
	oldState := s.state
	s.state = newState
	
	// 记录状态变更日志
	log.Debugf("Session %s state changed: %s -> %s", s.id, oldState.String(), newState.String())
	
	// 发布状态变更事件
	eventbus.GlobalEventBus().Publish(eventbus.NewBaseEvent(
		eventbus.EventSessionStateChanged,
		map[string]interface{}{
			"session_id": s.id,
			"old_state":  oldState.String(),
			"new_state":  newState.String(),
			"timestamp":  time.Now(),
		},
	))
}
// Start 启动会话（从StateReady转为StatePlaying），失败返回错误（如状态不允许）
func (s *BaseSession) Start() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.state != StateReady {
		return errors.New("session is not in ready state")
	}

	s.state = StatePlaying
	s.startTime = time.Now()
	// 发布会话开始事件到事件总线
	eventbus.GlobalEventBus().Publish(eventbus.NewBaseEvent(
		eventbus.EventSessionStarted,
		map[string]interface{}{
			"session_id": s.ID(),
			"startTime":  s.createAt,
		},
	))
	log.Infof("Session started: %s", s.ID())
	return nil
}

// Pause 暂停会话（仅StatePlaying状态可用），失败返回错误
func (s *BaseSession) Pause() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.state != StatePlaying {
		return errors.New("session is not in playing state")
	}
	s.pauseTime = time.Now()
	s.state = StatePaused
	// 发布会话暂停事件到事件总线   使用全局事件总线，这个操作是正确的，用单个事件总线不行，换句话说，这个东西就是在全局上进行操作的
	eventbus.GlobalEventBus().Publish(eventbus.NewBaseEvent(
		eventbus.EventSessionPaused,
		map[string]interface{}{
			"sessionID": s.id,
			"pauseTime": s.pauseTime,
		},
	))

	log.Infof("Session paused: %s", s.id)
	return nil
}

// Resume 恢复暂停的会话（从暂停状态回到StatePlaying），失败返回错误
func (s *BaseSession) Resume() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.state != StatePaused {
		return errors.New("session is not in paused state")
	}

	s.state = StatePlaying

	s.resumeTime = time.Now()

	// 计算暂停持续时间
	pauseDuration := s.resumeTime.Sub(s.pauseTime)
	s.totalPauseDuration += pauseDuration

	// 发布会话恢复事件到事件总线
	eventbus.GlobalEventBus().Publish(eventbus.NewBaseEvent(
		eventbus.EventSessionResumed,
		map[string]interface{}{
			"sessionID":     s.id,
			"resumeTime":    s.resumeTime,
			"pauseDuration": pauseDuration,
		},
	))

	log.Infof("Session resumed: %s", s.id)
	return nil
}

// End 结束会话（转为StateFinished），失败返回错误
func (s *BaseSession) End() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.state == StateFinished {
		return errors.New("session already ended")
	}
	s.endTime = time.Now()
	s.state = StateFinished
	// 计算会话总时长（减去暂停时间）
	totalDuration := s.endTime.Sub(s.startTime) - s.totalPauseDuration
	// 发布会话结束事件到事件总线
	eventbus.GlobalEventBus().Publish(eventbus.NewBaseEvent(
		eventbus.EventSessionEnded,
		map[string]interface{}{
			"sessionID":     s.id,
			"endTime":       s.endTime,
			"totalDuration": totalDuration,
		},
	))

	log.Infof("Session ended: %s", s.id)
	return nil
}

// NewBaseSession 创建基础会话实例，初始化会话ID、配置、玩家存储和创建时间
// 参数：
//
//	sessionID: 会话唯一标识（需上层保证唯一性，如通过UUID生成）
//	config: 会话配置（定义玩家数量、自动启动等规则）
//
// 返回值：
//
//	*BaseSession: 初始化后的基础会话实例
func NewBaseSession(sessionID string, config SessionConfig) *BaseSession {
	return &BaseSession{
		id:       sessionID,
		state:    StateIdle, // 初始状态为空闲
		config:   config,
		players:  make(map[string]bool), // 初始化玩家存储map
		createAt: time.Now(),            // 记录会话创建时间
	}
}

// ID 实现GameSession接口的ID方法，返回会话唯一标识
func (s *BaseSession) ID() string {
	return s.id // 直接返回初始化时设置的id，无需加锁（id不可修改）
}

// State 实现GameSession接口的State方法，返回会话当前状态
func (s *BaseSession) State() SessionState {
	s.mu.RLock()         // 加读锁：仅读取状态，不修改，允许并发读
	defer s.mu.RUnlock() // 函数退出时释放读锁
	return s.state
}


// AddPlayer 实现GameSession接口的AddPlayer方法，向会话添加玩家
// 参数：
//
//	playerID: 要添加的玩家唯一标识
//
// 返回值：
//
//	error: 成功返回nil；失败返回错误（状态不允许、会话满员、玩家已存在）
func (s *BaseSession) AddPlayer(playerID string) error {
	s.mu.Lock()         // 加写锁：修改玩家列表和状态，需保证并发安全
	defer s.mu.Unlock() // 函数退出时释放写锁

	// 1. 检查会话状态：仅Idle（空闲）或Matching（匹配中）状态允许添加玩家
	if s.state != StateIdle && s.state != StateMatching {
		return errors.New("session is not accepting new players")
	}

	// 2. 检查会话是否满员：玩家数达到MaxPlayers则无法添加
	if len(s.players) >= s.config.MaxPlayers {
		return errors.New("session is full")
	}

	// 3. 检查玩家是否已存在：避免重复添加同一玩家
	if _, exists := s.players[playerID]; exists {
		return errors.New("player already exists")
	}

	// 4. 添加玩家到会话
	s.players[playerID] = true

	// 5. 自动启动判断：若开启AutoStart且玩家数达到MinPlayers，将状态转为Ready（准备开始）
	if s.config.AutoStart && len(s.players) >= s.config.MinPlayers {
		s.state = StateReady
	}

	return nil
}

// RemovePlayer 实现GameSession接口的RemovePlayer方法，从会话移除玩家
// 参数：
//
//	playerID: 要移除的玩家唯一标识
//
// 返回值：
//
//	error: 成功返回nil；当前无特殊失败场景（即使玩家不存在，delete操作也不会报错）
func (s *BaseSession) RemovePlayer(playerID string) error {
	s.mu.Lock() // 加写锁：修改玩家列表和状态
	defer s.mu.Unlock()

	// 从玩家map中删除指定玩家（即使playerID不存在，delete也不会报错）
	delete(s.players, playerID)

	// 状态回滚：若当前状态是Ready（准备开始），且玩家数低于MinPlayers，回滚到Matching（匹配中）
	if len(s.players) < s.config.MinPlayers && s.state == StateReady {
		s.state = StateMatching
	}

	return nil
}

// GetPlayers 实现GameSession接口的GetPlayers方法，返回当前会话中所有玩家的ID列表
// 返回值：
//
//	[]string: 玩家ID列表（为避免外部修改内部数据，返回新创建的切片）
func (s *BaseSession) GetPlayers() []string {
	s.mu.RLock() // 加读锁：仅读取玩家列表，不修改
	defer s.mu.RUnlock()

	// 初始化切片（容量为玩家数，避免扩容）
	players := make([]string, 0, len(s.players))
	// 遍历玩家map，收集所有playerID
	for playerID := range s.players {
		players = append(players, playerID)
	}
	return players
}

// PlayerCount 实现GameSession接口的PlayerCount方法，返回当前会话中的玩家数量
// 返回值：
//
//	int: 玩家数量（通过len(players)获取）
func (s *BaseSession) PlayerCount() int {
	s.mu.RLock() // 加读锁：仅读取玩家数量
	defer s.mu.RUnlock()
	return len(s.players)
}

// IsFull 实现GameSession接口的IsFull方法，判断会话是否已达最大玩家数
// 返回值：
//
//	bool: true表示满员（无法加入新玩家），false表示未满
func (s *BaseSession) IsFull() bool {
	s.mu.RLock() // 加读锁：读取玩家数和MaxPlayers
	defer s.mu.RUnlock()
	return len(s.players) >= s.config.MaxPlayers
}

// IsEmpty 实现GameSession接口的IsEmpty方法，判断会话是否无玩家
// 返回值：
//
//	bool: true表示无玩家，false表示有玩家
func (s *BaseSession) IsEmpty() bool {
	s.mu.RLock() // 加读锁：读取玩家数
	defer s.mu.RUnlock()
	return len(s.players) == 0
}

// CanJoin 实现GameSession接口的CanJoin方法，判断当前是否允许新玩家加入
// 返回值：
//
//	bool: true表示可加入（状态为Idle/Matching且未达MaxPlayers），false表示不可加入
func (s *BaseSession) CanJoin() bool {
	s.mu.RLock() // 加读锁：读取状态和玩家数
	defer s.mu.RUnlock()
	// 两个条件同时满足：1. 状态是Idle或Matching；2. 玩家数未达MaxPlayers
	return (s.state == StateIdle || s.state == StateMatching) && len(s.players) < s.config.MaxPlayers
}

// 广播消息给所有玩家
func (s *BaseSession) Broadcast(message []byte) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	// 在实际实现中，这里应该通过网络发送消息给所有玩家
	// 目前先记录日志
	for playerID := range s.players {
		log.Debugf("Broadcasting to player %s: %s", playerID, string(message))
	}
	// // 发布会话广播事件
	// s.eventBus.Publish(event.NewSessionEvent(
	// 	"session.broadcaset",
	// 	s.id,
	// 	"",
	// 	map[string]interface{}{
	// 		"message_size": len(message),
	// 		"player_count": len(s.players),
	// 	},
	// ))
	return nil
}

// SendPlayer 发送消息给特定玩家
func (s *BaseSession) SendPlayer(playerID string, message []byte) error {
	s.mu.RLock()
	defer s.mu.RUnlock()

	if !s.players[playerID] {
		return errors.New("player not in session")
	}

	// 在实际实现中，这里应该通过网络发送消息给特定玩家
	log.Debugf("Sending to player %s: %s", playerID, string(message))

	return nil
}

func (s *BaseSession) GetConfig() SessionConfig {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.config
}

func (s *BaseSession) StartAt() *time.Time {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return &s.startTime
}


// GetState 获取会话状态（线程安全）
func (s *BaseSession) GetState() SessionState {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state
}

// CanStart 检查是否可以启动会话
func (s *BaseSession) CanStart() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	return s.state == StateReady && 
	       len(s.players) >= s.config.MinPlayers && 
	       len(s.players) <= s.config.MaxPlayers
}

// CanPause 检查是否可以暂停会话
func (s *BaseSession) CanPause() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state == StatePlaying
}

// CanResume 检查是否可以恢复会话
func (s *BaseSession) CanResume() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state == StatePaused
}

// CanEnd 检查是否可以结束会话
func (s *BaseSession) CanEnd() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.state == StatePlaying || s.state == StatePaused
}

// GetSessionInfo 获取会话详细信息（用于监控和调试）
func (s *BaseSession) GetSessionInfo() map[string]interface{} {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	players := make([]string, 0, len(s.players))
	for playerID := range s.players {
		players = append(players, playerID)
	}
	
	return map[string]interface{}{
		"id":            s.id,
		"state":         s.state.String(),
		"player_count":   len(s.players),
		"max_players":    s.config.MaxPlayers,
		"min_players":    s.config.MinPlayers,
		"created_at":    s.createAt,
		"players":       players,
		"is_full":       len(s.players) >= s.config.MaxPlayers,
		"can_join":      s.CanJoin(),
		"auto_start":    s.config.AutoStart,
		"reconnectable": s.config.Reconnectable,
	}
}

// UpdateConfig 更新会话配置（需要状态允许）
func (s *BaseSession) UpdateConfig(newConfig SessionConfig) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	
	// 只有在空闲或匹配状态才允许修改配置
	if s.state != StateIdle && s.state != StateMatching {
		return errors.New("cannot update config in current state")
	}
	
	// 验证新配置
	if newConfig.MaxPlayers < len(s.players) {
		return errors.New("max players cannot be less than current player count")
	}
	
	if newConfig.MinPlayers > newConfig.MaxPlayers {
		return errors.New("min players cannot be greater than max players")
	}
	
	s.config = newConfig
	return nil
}

// GetDuration 获取会话运行时长（考虑暂停时间）
func (s *BaseSession) GetDuration() time.Duration {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	if s.startTime.IsZero() {
		return 0
	}
	
	endTime := time.Now()
	if !s.endTime.IsZero() {
		endTime = s.endTime
	}
	
	return endTime.Sub(s.startTime) - s.totalPauseDuration
}

// IsExpired 检查会话是否已过期
func (s *BaseSession) IsExpired(timeout time.Duration) bool {
	s.mu.RLock()
	defer s.mu.RUnlock()
	
	// 只有空闲状态且超过超时时间的空会话才过期
	if s.state == StateIdle && time.Since(s.createAt) > timeout {
		return s.IsEmpty()
	}
	
	return false
}